#ifndef COMPLETITION_PORT_H
#define COMPLETITION_PORT_H

#include "AutoHandle.h"

#define ASSERT(ver) 

class CompletionPort
	: public AutoHandle
{
public:

    CompletionPort() :
        m_closeHandle(true)
    {
        // Do nothing
    }

    explicit CompletionPort(__in bool closeHandle) :
        m_closeHandle(closeHandle)
    {
        // Do nothing
    }

    CompletionPort(__in bool closeHandle,
                   __in_opt HANDLE handle) :
        m_closeHandle(closeHandle),
        AutoHandle(handle)
    {
        // Do nothing
    }

    ~CompletionPort()
    {
        if (!m_closeHandle)
        {
            Detach();
        }
    }

    __checkReturn HRESULT Create(__in DWORD threadCount)
    {
        Attach(::CreateIoCompletionPort(INVALID_HANDLE_VALUE,
                                        0, // no existing port
                                        0, // ignored
                                        threadCount));

        if (0 == m_h)
        {
            return HRESULT_FROM_WIN32(::GetLastError());
        }

        return S_OK;
    }

    __checkReturn HRESULT AssociateFile(__in HANDLE file,
                                        __in ULONG_PTR completionKey)
    {
        ASSERT(0 != file && INVALID_HANDLE_VALUE != file);
        ASSERT(0 != m_h);

        if (0 == ::CreateIoCompletionPort(file,
                                          m_h,
                                          completionKey,
                                          0)) // ignored
        {
            return HRESULT_FROM_WIN32(::GetLastError());
        }

        return S_OK;
    }

    __checkReturn HRESULT QueuePacket(__in DWORD bytesCopied,
                                      __in ULONG_PTR completionKey,
                                      __in OVERLAPPED* overlapped)
    {
        ASSERT(0 != m_h);

        if (!::PostQueuedCompletionStatus(m_h,
                                          bytesCopied,
                                          completionKey,
                                          overlapped))
        {
            return HRESULT_FROM_WIN32(::GetLastError());
        }

        return S_OK;
    }

    __checkReturn HRESULT DequeuePacket(__in DWORD milliseconds,
                                        __out DWORD& bytesCopied,
                                        __out ULONG_PTR& completionKey,
                                        __out OVERLAPPED*& overlapped)
    {
        ASSERT(0 != m_h);

        if (!::GetQueuedCompletionStatus(m_h,
                                         &bytesCopied,
                                         &completionKey,
                                         &overlapped,
                                         milliseconds))
        {
            return HRESULT_FROM_WIN32(::GetLastError());
        }

        return S_OK;
    }

private:

    CompletionPort(CompletionPort&);
    CompletionPort& operator=(CompletionPort&);

    bool m_closeHandle;

};

#endif